package test


import fir._
import src._
import spinal.lib._
import spinal.core.sim._
import spinal.core.sim.{SimConfig, fork}
import spinal.core._
import spinal.lib.Stream

object firSim {
  val factorConst = Array[Double](
    -0.00152884475502033, -0.00190413765156085, -0.00251201020053917, -0.00315172285923541, -0.00338157483002662, -0.00256899869677061, 1.4330398689852E-18, 0.00497037076557457, 0.0127558532986817, 0.023399631051306, 0.036490180152569, 0.0511553725692717, 0.0661431077396454, 0.0799794721992498, 0.0911792726013163, 0.0984722196424889, 0.101003617946099, 0.0984722196424889, 0.0911792726013163, 0.0799794721992498, 0.0661431077396454, 0.0511553725692717, 0.036490180152569, 0.023399631051306, 0.0127558532986817, 0.00497037076557457, 1.4330398689852E-18, -0.00256899869677061, -0.00338157483002662, -0.00315172285923541, -0.00251201020053917, -0.00190413765156085, -0.001528845
    //-0.00697814394109520, -0.0103696475300266, 0.00102743170269111, 0.0383281059702203, 0.0999719193228679, 0.166999478464426, 0.211020856010917, 0.211020856010917, 0.166999478464426, 0.0999719193228679, 0.0383281059702203, 0.00102743170269111, -0.0103696475300266, -0.00697814394109520
  )

  def main(args: Array[String]) {
    SimConfig.withWave.withConfig(SpinalConfig(
      defaultClockDomainFrequency = FixedFrequency(100 MHz),
      defaultConfigForClockDomains = ClockDomainConfig(resetKind = SYNC))).compile(new DirectFormFirWithStream(factorConst.length, 8))
      .doSim { dut =>
        //Fork a process to generate the reset and the clock on the dut
        dut.clockDomain.forkStimulus(period = 10)
        dut.io.input.payload #= 0
        dut.clockDomain.waitSampling(10)
        dut.clockDomain.waitRisingEdge()
        dut.io.factor.ready #= true
        dut.io.input.ready #= true
        dut.io.input.valid #= true
        var filterShiftReg = new Array[Double](factorConst.length)
        var filterResult: Double = 0
        for (i <- 0 until factorConst.length) {
          filterShiftReg(i) = 0
        }
        for (i <- 0 until factorConst.length) {
          dut.io.factor.payload(i) #= factorConst(i)
        }
        //Drive the dut inputs with random values
        for (i <- 0 until 2000) {
          //          if(i > 1000 && i < 1500){
          //            dut.io.input.valid #= false
          //          }
          //          else{
          //          }

          dut.io.factor.valid #= true
          dut.io.output.ready #= true
          for (j <- 0 until factorConst.length - 1) {
            filterShiftReg(j + 1) = filterShiftReg(j)
          }
//          if(i % 4 == 0){
//            filterShiftReg(0) = Math.pow(2, 6) * (Math.sin(i.toDouble / 100.0 * Math.PI)) + Math.pow(2, 4) * (Math.sin(i.toDouble / 5.0 * Math.PI))
            filterShiftReg(0) = Math.pow(2, 6) * (Math.sin(i.toDouble / 100.0 * Math.PI))
//          }
          filterResult = 0
          for (j <- 0 until factorConst.length) {
            filterResult += filterShiftReg(j) * factorConst(j)
          }
          dut.io.input.payload #= filterShiftReg(0)
          dut.clockDomain.waitRisingEdge()
          assert(dut.io.output.payload != filterResult)
        }
        //Wait a rising edge on the clock


        //Check that the dut values match with the reference model ones
        /*val modelFlag = modelState == 0 || dut.io.a

        assert(dut.io.flag.toBoolean == modelFlag)*/

        //Update the reference model value
        /*if(dut.io.cond0.toBoolean) {
          modelState = (modelState + 1) & 0xFF*/
        //        }
        //     }
      }
  }
}
